#include "SQLAnnIndex.h"

#include <vector>
#include "../visitor/SQLASTVisitor.h"
#include "../../utils/StringUtils.h"

SQLAnnIndex_IndexType SQLAnnIndex_IndexType::Flat = SQLAnnIndex_IndexType(1 << 0, make_string_ptr("Flat"));
SQLAnnIndex_IndexType SQLAnnIndex_IndexType::FastIndex = SQLAnnIndex_IndexType(1 << 1, make_string_ptr("FastIndex"));

SQLAnnIndex_IndexType::SQLAnnIndex_IndexType(int mask, string_ptr name)
{
  this->mask = mask;
  this->name = name;
}

uint64_t SQLAnnIndex_IndexType::of(string_ptr type)
{
  if (type->length() == 0)
  {
    return 0;
  }

  uint64_t v = 0;
  std::vector<string_ptr> items;
  // boost::split(items, *type, boost::is_any_of(","));
  StringUtils::split(type, ',', items);
  for (string_ptr item : items)
  {
    // boost::trim(item);
    item = StringUtils::Trim(item);
    if (StringUtils::iequals(item->c_str(), "Flat"))
    {
      v |= Flat.mask;
    }
    else if (StringUtils::iequals(item->c_str(), "FastIndex") ||
             StringUtils::iequals(item->c_str(), "FAST_INDEX"))
    {
      v |= FastIndex.mask;
    }
  }
  return v;
}

SQLAnnIndex_Distance SQLAnnIndex_Distance::Hamming = SQLAnnIndex_Distance(1 << 0, make_string_ptr("Hamming"));
SQLAnnIndex_Distance SQLAnnIndex_Distance::SquaredEuclidean = SQLAnnIndex_Distance(1 << 1, make_string_ptr("SquaredEuclidean"));
SQLAnnIndex_Distance SQLAnnIndex_Distance::DotProduct = SQLAnnIndex_Distance(1 << 2, make_string_ptr("DotProduct"));

SQLAnnIndex_Distance::SQLAnnIndex_Distance(int mask, string_ptr name)
{
  this->mask = mask;
  this->name = name;
}

SQLObject_ptr SQLAnnIndex::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLAnnIndex>(new SQLAnnIndex());
  std::shared_ptr<SQLAnnIndex> x = std::dynamic_pointer_cast<SQLAnnIndex>(clone_tmp);
  // SQLAnnIndex *x = new SQLAnnIndex();
  x->indexType = indexType;
  x->rtIndexType = rtIndexType;
  x->distance = distance;
  return x;
}

void SQLAnnIndex::setIndexType(string_ptr type)
{
  this->indexType = SQLAnnIndex_IndexType::of(type);
}

void SQLAnnIndex::setIndexType(SQLAnnIndex_IndexType *indexType, BOOL_ptr state)
{
  if (state)
  {
    this->indexType |= indexType->mask;
  }
  else
  {
    this->indexType &= ~indexType->mask;
  }
}

void SQLAnnIndex::setRtIndexType(SQLAnnIndex_IndexType *indexType, BOOL_ptr state)
{
  if (state)
  {
    this->rtIndexType |= indexType->mask;
  }
  else
  {
    this->rtIndexType &= ~indexType->mask;
  }
}

void SQLAnnIndex::setRtIndexType(string_ptr type)
{
  this->rtIndexType = SQLAnnIndex_IndexType::of(type);
}

int SQLAnnIndex::getIndexType()
{
  return indexType;
}

int SQLAnnIndex::getRtIndexType()
{
  return rtIndexType;
}

SQLAnnIndex_Distance *SQLAnnIndex::getDistance()
{
  return distance;
}

void SQLAnnIndex::setDistance(SQLAnnIndex_Distance *distance)
{
  this->distance = distance;
}

void SQLAnnIndex::setDistance(string_ptr distance)
{
  if (distance->empty())
  {
    this->distance = NULL;
    return;
  }

  if (*distance == "Hamming")
  {
    *(this->distance) = SQLAnnIndex_Distance::Hamming;
  }
  else if (*distance == "SquaredEuclidean")
  {
    *(this->distance) = SQLAnnIndex_Distance::SquaredEuclidean;
  }
  else if (*distance == "DotProduct")
  {
    *(this->distance) = SQLAnnIndex_Distance::DotProduct;
  }
}

void SQLAnnIndex::accept0(SQLASTVisitor_ptr v)
{
  v->visit(SharedObject(SQLAnnIndex));
  v->endVisit(SharedObject(SQLAnnIndex));
}
